﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Timer=System.Windows.Forms.Timer;
using System.Linq;


namespace StudyProcesses
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        static void SimpleWork()
        {
            
            MessageBox.Show(String.Format("Thread: {0}", Thread.CurrentThread.ManagedThreadId));
            Thread.Sleep(1000);
        }

        static Semaphore _semaforo = null;


        private void button1_Click(object sender, EventArgs e)
        {
            ThreadStart operation = new ThreadStart(SimpleWork);
            Thread[] allThreads = new Thread[5];

            for (int t = 0; t < 2; t++)
            {
                allThreads[t] = new Thread(operation);

                allThreads[t].Priority = ThreadPriority.Highest;

                allThreads[t].Start();

            }

            foreach (Thread t in allThreads)
            {
                t.Join();

            }


        }

     static void WorkWithOneParam(object pOggetto)
        {
            // Castare in questo modo è un rischio, perche' potrebbe arrivarmi un tipo non stringa
            //String stringa = (string) pOggetto;

            String stringa = pOggetto as string;

            if (String.IsNullOrEmpty(stringa))
            {
                throw new InvalidProgramException("Argomento non di tipo stringa!!!");

            }

            for (int x = 1; x < 3; x++ )
            {
                MessageBox.Show(String.Format("Stringa passata {0} - Ciclo n. {1} - Thread {2}", stringa, x, Thread.CurrentThread.ManagedThreadId));
                Thread.Sleep(500);
            }

        }


     private void button2_Click(object sender, EventArgs e)
        {
            // Utilizzo questo delegato in quanto voglio passare qualcosa al mio thread,
            // questo delegato vuole 1 argomento di tipo oggetto
            ParameterizedThreadStart operationWithParm = new ParameterizedThreadStart(WorkWithOneParam);

            Thread[] allThreads = new Thread[5];

            textBox1.Text = "Avvio threads...";

            for (int x = 0; x < 5; x++ )
                allThreads[x] = new Thread(operationWithParm);
            allThreads[0].Start("Primo");
            allThreads[1].Start("Secondo");

            allThreads[0].Join();
            allThreads[1].Join();

            textBox1.Text = "Conclusione di entrambi e threads";

            //allThreads[2].Start("Terzo");
            //allThreads[3].Start("Quarto");
            //allThreads[4].Start("Quinto");

        }

     public class Contatore
     {
        public static int conto;
     }

     public void IncrementaContatore()
     {


         
         // Blocco l'accesso al seguente codice da parte di altri threads
         lock (this)
         {
             //for (int x = 1; x <= 10000; x++)
             //    Contatore.conto = Contatore.conto + 1;
         }

         // Blocco con il monitor per un certo timeout
         Monitor.TryEnter(this, Timeout.Infinite);

         for (int x = 1; x <= 10000; x++)
             Contatore.conto = Contatore.conto + 1;

         Monitor.Exit(this);

         // Altro lock, ReaderWriterLock

         ReaderWriterLock rwLock = new ReaderWriterLock();
         rwLock.AcquireReaderLock(Timeout.Infinite);
         rwLock.ReleaseReaderLock();
         rwLock.AcquireWriterLock(200);
         rwLock.ReleaseWriterLock();

         // Molto piu' pesanti, ma utili se si vuole uscire da .net

         Mutex m = new Mutex();
         m.WaitOne(1000);

         // Fantastico c'è il semaphore che lavora con gli slot
         

         try
         {
             _semaforo = Semaphore.OpenExisting("VERDE-ROSSO-GIALLO");

         }
         catch (WaitHandleCannotBeOpenedException)
         {

             MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " - Semaforo inesistente!");
         }

         if (_semaforo == null)
         {
             _semaforo = new Semaphore(0, 1);
             MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " - Semaforo creato!");
         }

         //MessageBox.Show(Thread.CurrentThread.ManagedThreadId + " - Sto lavorando!");

         //_semaforo.Release(1);



     }
     
     private void button3_Click(object sender, EventArgs e)
     {
         Contatore.conto = 0;

         int cicli = 3;

         ThreadStart operation = new ThreadStart(IncrementaContatore);

         Thread[] allThreads = new Thread[cicli];

         for (int x = 0; x < cicli; x++)
         {
             allThreads[x] = new Thread(operation);
             allThreads[x].Start();
             Thread.Sleep(2000);
         }

         for (int x = 0; x < cicli; x++)
             allThreads[x].Join();

         //MessageBox.Show("Totale: " + Contatore.conto);


     }

     private int _totalClick;
     System.Threading.Timer tm;
 
     private void button4_Click(object sender, EventArgs e)
     {

         _totalClick = 0;
         System.Threading.TimerCallback callback = new System.Threading.TimerCallback(TickTick);

         tm = new System.Threading.Timer(callback, "solo 3", 0, 2000);

     }

        private void TickTick(object state)
        {
            string str = state as string;

            if (str != null)
            {

                Interlocked.Increment(ref _totalClick);
                
                if (_totalClick >= 3)
                    tm.Change(Timeout.Infinite, Timeout.Infinite);

               


                MessageBox.Show("Tick " + str);



            }
        }

        private void button5_Click(object sender, EventArgs e)
        {

            string fullpath = @"c:\temp\msdia80.dll";
            byte[] buffer = new byte[10000000];

            //fullpath = Path.ChangeExtension(fullpath, "txt");

            // Gli dico che posso leggere un file binario in modalita asincrona
            FileStream fs = new FileStream(fullpath, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous);

            // Avvio la lettura e gli dico che metodo chiamare al termina della lettura e posso anche passargli un oggetto
            IAsyncResult result = fs.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(callmenowDelegate), "ciupa");

            MessageBox.Show("Started. Iscompleted? " + result.IsCompleted);


            Thread.Sleep(1000);


            // Con questo metodo il codice si ferma qui e aspetta il termine delle operazioni asincrone,
            // solo al termine di questo tutto continua; è preferibile testare il iscompleted in un ciclo while not
            // NB. Le eccezioni verranno catturate QUI e non al momento dell'errore
            int numBytes = fs.EndRead(result);

            MessageBox.Show("bytes: " + numBytes + " - " +  buffer[0].ToString());

            fs.Close();

            fs.Dispose();

            fs = null;



        }



        private void callmenowDelegate(IAsyncResult ar)
        {
           
            
            string myFs;

            myFs = (string) ar.AsyncState;

            MessageBox.Show("End. " + myFs  + ". Iscompleted? " + ar.IsCompleted);
            
        }

        private void button6_Click(object sender, EventArgs e)
        {

            int minThreads;
            int minPorts;
            int maxThreads;
            int maxPorts;

            WaitCallback poolthreadItem = new WaitCallback(WorkWithOneParam);


            // Setto il numero max di threads nel mio pool
            ThreadPool.SetMinThreads(1, 100);
            ThreadPool.SetMaxThreads(2, 200);

            ThreadPool.GetMinThreads(out minThreads, out minPorts);
            ThreadPool.GetMaxThreads(out maxThreads, out maxPorts);



            MessageBox.Show(String.Format("Thread, min: {0} max: {1}. Ports, min: {2} max: {3}", minThreads, maxThreads, minPorts, maxPorts));
 


            if (!ThreadPool.QueueUserWorkItem(poolthreadItem, "threadpooling1!"))
            {
                MessageBox.Show("Impossibile accodare il task");
            }

            if (!ThreadPool.QueueUserWorkItem(poolthreadItem, "threadpooling2!"))
            {
                MessageBox.Show("Impossibile accodare il task");
            }

            if (!ThreadPool.QueueUserWorkItem(poolthreadItem, "threadpooling3!"))
            {
                MessageBox.Show("Impossibile accodare il task");
            }

            ThreadPool.GetMinThreads(out minThreads, out minPorts);
            ThreadPool.GetMaxThreads(out maxThreads, out maxPorts);

            MessageBox.Show(String.Format("Thread, min: {0} max: {1}. Ports, min: {2} max: {3}", minThreads, maxThreads, minPorts, maxPorts));



        }

        private void button7_Click(object sender, EventArgs e)
        {

            Mutex m = null;

            try
            {
                Debug.WriteLine("Sono in debug!");
                m = Mutex.OpenExisting("MYMUTEX");
            }
            catch (WaitHandleCannotBeOpenedException)
            {
                // Se entra qui significa che non esiste nessun mutex con quel nome, e' normale
                MessageBox.Show("non esiste!");
                //Debug.Fail("non esiste");
            }

            Debug.Assert(m == null, "ahi ahi ahi, il mutex non esiste!");


            if (m == null)
            {
                // Nessun mutex gia' attivo, lo creo io
                m = new Mutex(true, "MYMUTEX");

            }
            else
            {
                // Il mutex c'e' gia'!!!
                MessageBox.Show("mutex gia' in corso, attendi il turno!");
                m.Close();
                return;
            }

            WaitOrTimerCallback waitOrTimer = new WaitOrTimerCallback(MutexFirato);

            //ThreadPool.RegisterWaitForSingleObject(m, waitOrTimer, "fired", 5000, true );

            MessageBox.Show("Faccio tutto io");
            m.ReleaseMutex();

            m.Close();

            m = null;


        }

        public void MutexFirato(object obj, bool timeOut )
        {
            string str = obj as string;
            if (timeOut)
                MessageBox.Show("Mutex timeout");
            else
                MessageBox.Show("Mutex segnalato " + str);

        }

        private void button8_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Start");

            Process thisProcess;

            thisProcess = Process.GetCurrentProcess();
            Console.WriteLine("Processo corrente: " + thisProcess);

            Process processId2;

            processId2 = Process.GetProcessById(2072);
            Console.WriteLine("Processo #2: " + processId2);

            // da qui in poi faccio riferimento al performance counter grafico sulla form
            string categoria = performanceCounter1.CategoryName;

            Console.WriteLine("CounterName: " + performanceCounter1.CategoryName);

            if (PerformanceCounterCategory.Exists(categoria))
            {
                Console.WriteLine(categoria + " esiste");
                PerformanceCounterCategory[] categorie = PerformanceCounterCategory.GetCategories();

                foreach (PerformanceCounterCategory thiscategoria in categorie)
                {
                    //Console.WriteLine(thiscategoria.CategoryName + " - " + thiscategoria.CategoryType + " - " + thiscategoria.CategoryHelp);
                }


            }



           

            // Discorso performances, da rividere
            PerformanceCounterCategory DemoCounter = new PerformanceCounterCategory(categoria);
            InstanceDataCollectionCollection DemoCollection = DemoCounter.ReadCategory();

            //DemoCollection.ToString;
            foreach (var istanza in DemoCollection)
            {
                Console.WriteLine(istanza.ToString());
            }

            // Otteniamo un po di informazioni aggiuntive
            //PerformanceCounter HeapCounter = new PerformanceCounter(".NET CLR Memory", "# Byte in all Heaps");
            //HeapCounter.InstanceName = "_Global_";

            //Console.WriteLine("Heap: " + HeapCounter.NextValue().ToString());



            // Avvio processo prendendo il nome da una label
            ProcessStartInfo Info = new ProcessStartInfo();
            Info.FileName = this.textBox1.Text;
            //Process.Start(@Info);
            // Avvio processo tramite nome dell'applicazione
            //Process.Start("notepad");

            // Avvio processo con passaggio di argomenti
            Info.FileName = "notepad";
            Info.Arguments = @"c:\temp\leggimi2.txt";
            //Process.Start(@Info);





        }

        private void button9_Click(object sender, EventArgs e)
        {
            int[] listaNumeri = new int[5] {33, 41, 40, 10, 100};

            // Proviamo il Linq per estrarre i numeri pari
            // e anche ordinati

            IEnumerable<int> query = 
                        from nummm in listaNumeri
                        let totale = listaNumeri.First()
                        where (nummm > totale)
                        orderby nummm ascending 
                            select nummm;

           
            MessageBox.Show("totale: " + query.Count()); ;


            foreach (int num in query)
            {
                MessageBox.Show(num.ToString());
            }





        }
    }
}
